package com.nbut.filesystem;

import java.awt.Desktop;
import java.io.*;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;

/**
 *文件相关操作类
 */
public abstract class FileAction {
    /**
     * 创建文件
     * @param userFileAddr 用户的文件目录路径
     * @param virtualName 文件虚拟名称（在文件系统中显示的名称）
     * @param user 用户实体
     * @return 是否创建成功
     * @throws IOException io异常，可能是由于创建文件时失败而抛出
     */
    public static boolean create(String userFileAddr,String virtualName,User user) throws IOException {
        //检查文件名合法性
        if(isNotFileName(virtualName)) return false;
        //获取用户文件表
        UserFileList userFileList = user.getUserFileList();
        String realName;
        //获取空闲的真实文件名列表
        LinkedList<String> freeFileName = userFileList.getFreeFileName();
        //获取用户文件表
        HashMap<String,String> userLib = userFileList.getLibMap();
        //如果用户文件表中已经有同名文件，则直接返回
        if(!userLib.containsKey(virtualName)) {
            if (freeFileName.isEmpty()) {
                //若空闲文件表为空，则根据用户文件表的大小来决定真实文件名
                realName = "file" + userFileList.getLibMap().size() + "." + virtualName.split("\\.")[1];
            } else {
                //空闲文件表不为空，则弹出一个真实文件名
                realName = freeFileName.pop();
            }
            //根据真实文件名创建文件
            File file = new File(userFileAddr + realName);
            if (!file.exists()) {
                if (file.createNewFile()) {
                    //更新用户文件表
                    userLib.put(virtualName, realName);
                    return true;
                }
            }
        }
        return false;
    }

    /**
     * 删除文件
     * @param userFileAddr 用户的文件目录路径
     * @param virtualName 文件虚拟名称（在文件系统中显示的名称）
     * @param user 用户实体
     * @return 是否删除成功
     */
    public static boolean delete(String userFileAddr,String virtualName,User user){
        //检查文件名合法性
        if(isNotFileName(virtualName)) return false;
        //获取用户文件表
        UserFileList userFileList = user.getUserFileList();
        //获取空闲的真实文件名列表
        LinkedList<String> freeFileName = userFileList.getFreeFileName();
        //获取用户文件表
        HashMap<String,String> userLib = userFileList.getLibMap();
        //如果文件表中不存在文件名，则直接返回
        if(userLib.containsKey(virtualName)) {
            //获取真实文件名
            String realName = userLib.get(virtualName);
            //真实文件
            File file = new File(userFileAddr + realName);
            if (file.exists()) {
                if(file.delete()) {
                    //将要删除的真实文件的文件名加入空闲文件名表
                    freeFileName.push(realName);
                    //移除用户文件表中相对应的项
                    userLib.remove(virtualName);
                    return true;
                }
            }
        }
        return false;
    }

    /**
     * 打开文件
     * @param file 要打开的文件
     * @throws IOException 打开失败时会抛出异常
     */
    public static void open(File file) throws IOException {
        //使用外部库函数打开文件
        Desktop.getDesktop().open(file);
    }

    /**
     * 读取文件
     * @param file 要读取的文件
     * @return 读取到的内容
     * @throws IOException 读取数据时出错可能会抛出
     */
    public static String read(File file) throws IOException {
        //检查文件名合法性
        if(isNotFileName(file.getName())) return null;
        StringBuilder sb = new StringBuilder();
        //一次最多读取1024个字符
        char[] chars = new char[1024];
        try (FileReader fileReader = new FileReader(file)) {
            //只要还有剩余字符就继续读取
            while (fileReader.read(chars) > 0) {
                sb.append(new String(chars).trim());
            }
            //关闭流
            fileReader.close();
        }
        return sb.toString();
    }

    /**
     * 写入文件
     * @param file 要写入的文件
     * @param text 要写入的内容（字符串）
     * @throws IOException 写入数据时若文件不存在可能会抛出
     */
    public static void write(File file,String text) throws IOException {
        if(isNotFileName(file.getName())) return;
        FileWriter writer = new FileWriter(file,true);
        //将文件内容写入
        writer.write(text);
        writer.write("\r\n");
        //刷新缓存区，保证数据完整写入
        writer.flush();
        //关闭流
        writer.close();
    }

    /**
     * 检查文件名合法性
     * 内部工具函数（外部不可调用）
     * @param name 文件名
     * @return 如果不是文件名就为真，否则为假
     */
    private static boolean isNotFileName(String name){
        String[] names = name.split("\\.");
        return names.length != 2;
    }
}
